#import <Foundation/NSGeometry.h>

/*!
 * @function CHFitSizeProportionallyInRect
 * @param size the Size to fit the rect in
 * @param rect the Rect
 * @abstract Returns a propertionally scaled down rect which fits in the given size
 */
FOUNDATION_STATIC_INLINE NSRect CHFitSizeProportionallyInRect (NSSize size, NSRect rect)
{
  NSRect a;
  if (size.width/rect.size.width > size.height/rect.size.height) {
    float scale = size.height/size.width;
    a.size.width = rect.size.width;
    a.size.height = a.size.width * scale;
    a.origin.x = rect.origin.x + rect.size.width/2 - a.size.width/2;
    a.origin.y = rect.origin.y + rect.size.height/2 - a.size.height/2;;
  } else {
    float scale = size.width/size.height;
    a.size.height = rect.size.height;
    a.size.width = a.size.height * scale;
    a.origin.x = rect.origin.x + rect.size.width/2 - a.size.width/2;
    a.origin.y = rect.origin.y + rect.size.height/2 - a.size.height/2;
  }
  return a;
}

/*!
 * @function CHLogRect
 * @param r the rect to log
 * Writes a description of the rect to the standard out
 */
FOUNDATION_STATIC_INLINE void CHLogRect (NSRect r)
{
  NSLog(@"x:%f y:%f w:%f h:%f",r.origin.x,r.origin.y,r.size.width,r.size.height);
}

/*!
 * @function CHLogSize
 * @param s the size to log
 * Writes a description of the size to the standard out
 */
FOUNDATION_STATIC_INLINE void CHLogSize (NSSize s)
{
  NSLog(@"w:%f h:%f",s.width,s.height);
}

/*!
 * @function CHLogPoint
 * @param p the point to log
 * Writes a description of the point to the standard out
 */
FOUNDATION_STATIC_INLINE void CHLogPoint (NSPoint p)
{
  NSLog(@"x:%f y:%f",p.x,p.y);
}

/*!
 * @function CHIntRect
 * @param r the rect to make integral
 * The rect is cast to an int
 */
FOUNDATION_STATIC_INLINE NSRect CHIntRect (NSRect r)
{
  r.origin.x    = (NSInteger)r.origin.x;
  r.origin.y    = (NSInteger)r.origin.y;
  r.size.width  = (NSInteger)r.size.width;
  r.size.height = (NSInteger)r.size.height;
  return r;
}

/*!
 * @function CHIntSize
 * @param s the size to make integral
 * The size is cast to an int
 */
FOUNDATION_STATIC_INLINE NSSize CHIntSize (NSSize s)
{
  s.width   = (NSInteger)s.width;
  s.height  = (NSInteger)s.height;
  return s;
}

/*!
 * @function CHIntPoint
 * @param p the point to make integral
 * The point is cast to an int
 */
FOUNDATION_STATIC_INLINE NSPoint CHIntPoint (NSPoint p)
{
  p.x = (NSInteger)p.x;
  p.y = (NSInteger)p.y;
  return p;
}

/*!
 * @function CHRectFromSize
 * @param s the size for the new rect
 * Creates a rect from an NSSize with NSZeroPoint as origin
 */
FOUNDATION_STATIC_INLINE NSRect CHRectFromSize (NSSize s)
{
  NSRect r;
  r.size    = s;
  r.origin  = NSZeroPoint;
  return r;
}

/*!
 * @function CHCropRect
 * @param r the r to inset
 * @param i the amount
 * Increases the origin by i and decreases the size with i
 */
FOUNDATION_STATIC_INLINE NSRect CHCropRect (NSRect r, int i)
{
  r.origin.x    +=i;
  r.origin.y    +=i;
  r.size.width  -=i+i;
  r.size.height -=i+i;
  return r;
}

/*!
 * @function CHExpandRect
 * @param r the r to inset
 * @param i the amount
 * Decreases the origin by i and increases the size with i*2
 */
FOUNDATION_STATIC_INLINE NSRect CHExpandRect (NSRect r, int i)
{
  r.origin.x    -=i;
  r.origin.y    -=i;
  r.size.width  +=i+i*2;
  r.size.height +=i+i*2;
  return r;
}

/*!
 * @function CHRelativeRect
 * @param r the inner rect
 * @param outer the outer rect
 * Returns a rect which is r releative to outer (measuring from 0 to 1)
 */
FOUNDATION_STATIC_INLINE NSRect CHRelativeRect(NSRect r, NSRect outer)
{
  r.origin.x    -= outer.origin.x;
  r.origin.y    -= outer.origin.y;
  r.origin.x    /= outer.size.width;
  r.origin.y    /= outer.size.height;
  r.size.width  /= outer.size.width;
  r.size.height /= outer.size.height;
  return r;
}

/*!
 * @function CHAbsoluteRect
 * @param r the inner rect
 * @param outer the outer rect
 * Returns an absolute rect which is equal to r which was releative to outer (measured from 0 to 1)
 */
FOUNDATION_STATIC_INLINE NSRect CHAbsoluteRect(NSRect r, NSRect outer)
{
  r.origin.x    *= outer.size.width;
  r.origin.y    *= outer.size.height;
  r.origin.x    += outer.origin.x;
  r.origin.y    += outer.origin.y;
  r.size.width  *= outer.size.width;
  r.size.height *= outer.size.height;
  return r;
}

/*!
 * @function CHRelativePoint
 * @param p the inner point
 * @param outer the outer rect
 * Returns a point which is p releative to outer (measuring from 0 to 1)
 */
FOUNDATION_STATIC_INLINE NSPoint CHRelativePoint(NSPoint p, NSRect outer)
{
  p.x -= outer.origin.x;
  p.y -= outer.origin.y;
  p.x /= outer.size.width;
  p.y /= outer.size.height;
  return p;
}

/*!
 * @function CHAbsolutePoint
 * @param p the inner point
 * @param outer the outer rect
 * Returns an absolute point which is equal to p which was releative to outer (measured from 0 to 1)
 */
FOUNDATION_STATIC_INLINE NSPoint CHAbsolutePoint(NSPoint p, NSRect outer)
{
  p.x *= outer.size.width;
  p.y *= outer.size.height;
  p.x += outer.origin.x;
  p.y += outer.origin.y;
  return p;
}

/*!
 * @function CHCenterSizeInRect
 * @param s the size
 * @param outer the outer rect
 * Returns a new rect where its size is equal to s and its origin such that s is centered in outer
 */
FOUNDATION_STATIC_INLINE NSRect CHCenterSizeInRect(NSSize s, NSRect outer)
{
  NSRect r;
  r.size      = s;
  r.origin.x  = (outer.size.width-s.width)/2   + outer.origin.x;
  r.origin.y  = (outer.size.height-s.height)/2 + outer.origin.y;
  return r;
}

/*!
 * @function CHRectWithMarginAroundPoint
 * @param margin the margin to take around the point
 * @param p the point to create a rect around
 * Returns a new rect with the point as its center and with a margin around it
 */
FOUNDATION_STATIC_INLINE NSRect CHRectWithMarginAroundPoint(float margin, NSPoint p)
{
  NSRect r;
  r.origin.x    = p.x - margin;
  r.origin.y    = p.y - margin;
  r.size.width  = margin*2.0;
  r.size.height = margin*2.0;
  return r;
}

FOUNDATION_STATIC_INLINE NSRect CHSizeCenteredAroundPoint(NSSize s, NSPoint p)
{
  NSRect r;
  r.origin.x = p.x - s.width/2;
  r.origin.y = p.y - s.height/2;
  r.size = s;
  return r;
}

FOUNDATION_STATIC_INLINE NSPoint CHRelativePointFromRectToRect(NSPoint p, NSRect fromRect, NSRect toRect)
{
  return CHRelativePoint(CHAbsolutePoint(p, fromRect), toRect);
}

FOUNDATION_STATIC_INLINE BOOL CHPointsEqualWithMargin(NSPoint p1, NSPoint p2, int margin)
{
  return NSPointInRect(p1, CHRectWithMarginAroundPoint(10,p2));
}